#!/bin/bash
###############################################################################
#       脚本名称: log_engine.sh
#       功能描述: 日志处理引擎,负责事件构建、过滤、格式化和分发
#       作者: 林再来
#       日期: 2025-11-03
#       版本: 2.0
#       功能:
#           1、构建日志事件对象(JSON格式)
#           2、应用过滤器链(级别过滤等)
#           3、分发到各个Appender
#           4、协调Formatter进行格式化
#           5、收集上下文信息(脚本名、行号等)
#           6、集成缓冲区管理(v2.0)
#           7、集成上下文管理(v2.0)
#           8、集成数据脱敏(v2.0)
#           9、集成过滤器系统(v2.0)
#       依赖(插件/命令):
#           无
###############################################################################

# 防止重复加载
[[ -n "${_LOG_ENGINE_LOADED:-}" ]] && return 0
readonly _LOG_ENGINE_LOADED=1

# 加载依赖模块
_LOG_ENGINE_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "${_LOG_ENGINE_DIR}/log_level.sh"
source "${_LOG_ENGINE_DIR}/log_buffer.sh"        # 先加载buffer(定义DEFAULT_BUFFER_SIZE)
source "${_LOG_ENGINE_DIR}/log_config.sh"        # 再加载config(使用DEFAULT_BUFFER_SIZE)
source "${_LOG_ENGINE_DIR}/../formatter/formatter_plain.sh"
source "${_LOG_ENGINE_DIR}/../formatter/formatter_json.sh"
source "${_LOG_ENGINE_DIR}/../appender/appender_console.sh"
source "${_LOG_ENGINE_DIR}/../appender/appender_file.sh"

# v2.0新功能模块
source "${_LOG_ENGINE_DIR}/log_context.sh"
source "${_LOG_ENGINE_DIR}/log_sanitizer.sh"
source "${_LOG_ENGINE_DIR}/../filters/filter_level.sh"
source "${_LOG_ENGINE_DIR}/../filters/filter_pattern.sh"
source "${_LOG_ENGINE_DIR}/../filters/filter_rate_limit.sh"
source "${_LOG_ENGINE_DIR}/log_async.sh"
source "${_LOG_ENGINE_DIR}/log_rotation.sh"

#-----------------------------------------------------------------------------
# 全局变量
#-----------------------------------------------------------------------------
# 已初始化的appender列表
declare -ga _LOG_ENGINE_APPENDERS=()
# 引擎初始化标志
declare -g _LOG_ENGINE_INITIALIZED="false"

#-----------------------------------------------------------------------------
# 函数: 初始化日志引擎
# 返回: 0-成功, 1-失败
#-----------------------------------------------------------------------------
function _log_engine_init() {
    # 防重复初始化
    if [[ "$_LOG_ENGINE_INITIALIZED" == "true" ]]; then
        return 0
    fi
    
    # 检查配置是否已初始化
    if ! log_config_is_initialized; then
        echo "错误: 配置未初始化,无法启动日志引擎" >&2
        return 1
    fi
    
    # 清空appender列表（防止残留）
    _LOG_ENGINE_APPENDERS=()
    
    # 获取所有启用的appender
    local enabled_appenders=$(log_config_get_enabled_appenders)
    
    if [[ -z "$enabled_appenders" ]]; then
        # 没有配置appender,使用默认控制台输出
        _appender_console_init "default_console"
        _LOG_ENGINE_APPENDERS+=("default_console:console")
    else
        # 初始化所有启用的appender
        for idx in $enabled_appenders; do
            local name=$(log_config_get "appender.$idx.name")
            local type=$(log_config_get "appender.$idx.type")
            
            case "$type" in
                console)
                    _appender_console_init "$name"
                    
                    # 设置配置
                    local color=$(log_config_get "appender.$idx.color" "auto")
                    local target=$(log_config_get "appender.$idx.target" "stdout")
                    _appender_console_set_config "$name" "color" "$color"
                    _appender_console_set_config "$name" "target" "$target"
                    ;;
                file)
                    _appender_file_init "$name"
                    
                    # 设置配置
                    local file=$(log_config_get "appender.$idx.file" "logs/app/app.log")
                    local max_size=$(log_config_get "appender.$idx.max_size" "100M")
                    local max_files=$(log_config_get "appender.$idx.max_files" "10")
                    local strategy=$(log_config_get "appender.$idx.rotation_strategy" "size")
                    local compress=$(log_config_get "appender.$idx.compress" "false")
                    
                    _appender_file_set_config "$name" "file" "$file"
                    _appender_file_set_config "$name" "max_size" "$max_size"
                    _appender_file_set_config "$name" "max_files" "$max_files"
                    _appender_file_set_config "$name" "rotation_strategy" "$strategy"
                    _appender_file_set_config "$name" "compress" "$compress"
                    ;;
                *)
                    echo "警告: 未实现的appender类型: $type" >&2
                    continue
                    ;;
            esac
            
            _LOG_ENGINE_APPENDERS+=("$name:$type:$idx")
        done
    fi
    
    _LOG_ENGINE_INITIALIZED="true"
    return 0
}

#-----------------------------------------------------------------------------
# 函数: 构建日志事件对象
# 参数: $1 - 日志级别
#       $2 - 模块名(可选,默认main)
#       $3 - 日志消息
#       其余参数 - 额外上下文(key=value格式)
# 返回: 输出JSON格式的事件对象
#-----------------------------------------------------------------------------
function _log_build_event() {
    local level="$1"
    local module="${2:-main}"
    local message="$3"
    shift 3 || shift $#
    
    # 获取时间戳
    local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
    
    # 获取调用栈信息
    local caller_info="${BASH_SOURCE[2]:-unknown}:${BASH_LINENO[1]:-0}"
    local script_name=$(basename "${BASH_SOURCE[2]:-unknown}")
    local line_number="${BASH_LINENO[1]:-0}"
    local function_name="${FUNCNAME[2]:-main}"
    
    # 获取进程信息
    local pid="$$"
    local hostname="${HOSTNAME:-$(hostname 2>/dev/null || echo 'unknown')}"
    local username="${USER:-$(whoami 2>/dev/null || echo 'unknown')}"
    
    # 获取追踪ID(如果环境变量中有)
    local trace_id="${LOG_TRACE_ID:-}"
    
    # 构建JSON事件
    local event="{"
    event+="\"timestamp\":\"$timestamp\","
    event+="\"level\":\"$level\","
    event+="\"message\":\"$message\","
    event+="\"module\":\"$module\","
    event+="\"script\":\"$script_name\","
    event+="\"line\":\"$line_number\","
    event+="\"function\":\"$function_name\","
    event+="\"pid\":\"$pid\","
    event+="\"hostname\":\"$hostname\","
    event+="\"username\":\"$username\""
    
    if [[ -n "$trace_id" ]]; then
        event+=",\"trace_id\":\"$trace_id\""
    fi
    
    # 添加额外上下文
    if [[ $# -gt 0 ]]; then
        event+=",\"extra\":{"
        local first=true
        for kv in "$@"; do
            if [[ "$kv" =~ ^([^=]+)=(.*)$ ]]; then
                local key="${BASH_REMATCH[1]}"
                local value="${BASH_REMATCH[2]}"
                
                if [[ "$first" == true ]]; then
                    first=false
                else
                    event+=","
                fi
                
                # 简单转义
                value="${value//\\/\\\\}"
                value="${value//\"/\\\"}"
                event+="\"$key\":\"$value\""
            fi
        done
        event+="}"
    fi
    
    event+="}"
    echo "$event"
}

#-----------------------------------------------------------------------------
# 函数: 应用过滤器
# 参数: $1 - 日志事件JSON
#       $2 - appender索引
# 返回: 0-通过, 1-拒绝
#-----------------------------------------------------------------------------
function _log_apply_filters() {
    local event="$1"
    local appender_idx="$2"
    
    # 提取日志级别
    local event_level=$(echo "$event" | grep -oP '(?<="level":")[^"]*')
    local appender_level=$(log_config_get "appender.$appender_idx.level" "INFO")
    
    # 级别过滤
    if ! _log_should_log "$event_level" "$appender_level"; then
        return 1
    fi
    
    # TODO: 应用其他过滤器(正则、频率限制等)
    
    return 0
}

#-----------------------------------------------------------------------------
# 函数: 格式化日志
# 参数: $1 - 日志事件JSON
#       $2 - 格式化器类型(plain/json)
#       $3 - 格式化器名称(可选)
# 返回: 输出格式化后的文本
#-----------------------------------------------------------------------------
function _log_format() {
    local event="$1"
    local formatter_type="$2"
    local formatter_name="${3:-$formatter_type}"
    
    case "$formatter_type" in
        plain)
            formatter_plain_format "$event" "$formatter_name"
            ;;
        json)
            formatter_json_format "$event" "$formatter_name"
            ;;
        *)
            # 未知格式化器,使用plain
            formatter_plain_format "$event" "plain"
            ;;
    esac
}

#-----------------------------------------------------------------------------
# 函数: 分发日志到所有appender
# 参数: $1 - 日志事件JSON
# 返回: 0-成功
#-----------------------------------------------------------------------------
function _log_dispatch() {
    local event="$1"
    
    # 遍历所有appender
    for appender_info in "${_LOG_ENGINE_APPENDERS[@]}"; do
        # 解析appender信息: name:type:idx
        IFS=':' read -r name type idx <<< "$appender_info"
        
        # 默认console没有idx
        [[ -z "$idx" ]] && idx=""
        
        # 应用过滤器
        if [[ -n "$idx" ]] && ! _log_apply_filters "$event" "$idx"; then
            continue
        fi
        
        # 获取格式化器类型
        local formatter_type
        if [[ -n "$idx" ]]; then
            formatter_type=$(log_config_get "appender.$idx.formatter" "plain")
        else
            formatter_type="plain"
        fi
        
        # 格式化日志
        local formatted=$(_log_format "$event" "$formatter_type" "$name")
        
        # 写入appender
        case "$type" in
            console)
                _appender_console_write "$name" "$formatted" "$event"
                ;;
            file)
                _appender_file_write "$name" "$formatted" "$event"
                ;;
        esac
    done
    
    return 0
}

#-----------------------------------------------------------------------------
# 函数: 处理日志(主入口)
# 参数: $1 - 日志级别
#       $2 - 模块名(可选,默认main)
#       $3 - 日志消息
#       其余参数 - 额外上下文
# 返回: 0-成功
#-----------------------------------------------------------------------------
function _log_process() {
    local level="$1"
    local module="${2:-main}"
    local message="$3"
    shift 3 || shift $#
    
    # 检查引擎是否已初始化
    if [[ "$_LOG_ENGINE_INITIALIZED" != "true" ]]; then
        # 未初始化,使用简单输出
        echo "[${level}] [${module}] $(date '+%Y-%m-%d %H:%M:%S') - ${message}" >&2
        return 0
    fi
    
    # 快速级别判断(全局级别)
    local global_level=$(log_config_get "global.level" "INFO")
    if ! _log_should_log "$level" "$global_level"; then
        return 0
    fi
    
    # 构建事件
    local event=$(_log_build_event "$level" "$module" "$message" "$@")
    
    # 分发到所有appender
    _log_dispatch "$event"
    
    return 0
}

#-----------------------------------------------------------------------------
# 函数: 关闭日志引擎
# 返回: 0-成功
#-----------------------------------------------------------------------------
function _log_engine_cleanup() {
    # 刷新所有appender
    for appender_info in "${_LOG_ENGINE_APPENDERS[@]}"; do
        IFS=':' read -r name type _ <<< "$appender_info"
        
        case "$type" in
            console)
                _appender_console_flush "$name"
                _appender_console_close "$name"
                ;;
            file)
                _appender_file_flush "$name"
                _appender_file_close "$name"
                ;;
        esac
    done
    
    # 清空appender列表
    _LOG_ENGINE_APPENDERS=()
    _LOG_ENGINE_INITIALIZED="false"
    
    return 0
}

#-----------------------------------------------------------------------------
# 测试函数
#-----------------------------------------------------------------------------
function _log_engine_test() {
    echo "=== 日志引擎模块测试 ==="
    
    # 查找配置文件
    local test_config="${PROJECT_ROOT}/config/base/logger.yaml"
    
    if [[ ! -f "$test_config" ]]; then
        echo "警告: 测试配置文件不存在: $test_config"
        echo "跳过测试"
        return 0
    fi
    
    echo ""
    echo "1. 初始化配置和引擎:"
    log_config_init "$test_config"
    _log_engine_init
    echo "  ✓ 引擎初始化成功"
    
    echo ""
    echo "2. 测试日志输出:"
    _log_process "INFO" "这是一条INFO级别的日志" "test"
    _log_process "WARN" "这是一条WARN级别的日志" "test" "key1=value1" "key2=value2"
    _log_process "ERROR" "这是一条ERROR级别的日志" "test"
    _log_process "DEBUG" "这是一条DEBUG级别的日志(可能被过滤)" "test"
    
    echo ""
    echo "3. 测试带追踪ID的日志:"
    export LOG_TRACE_ID="req-test-12345"
    _log_process "INFO" "带追踪ID的日志" "test"
    unset LOG_TRACE_ID
    
    echo ""
    echo "4. 清理引擎:"
    _log_engine_cleanup
    echo "  ✓ 引擎清理成功"
}

# 如果直接执行此脚本,运行测试
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
    _log_engine_test
fi

